package com.sz.common.base.dao.ext.impl;

import com.sz.common.base.dao.ext.DaoExt;
import com.sz.common.base.dao.ext.EntityDao;
import com.sz.common.base.dao.ext.FieldExp;
import com.sz.common.base.dao.ext.FieldExpBuilder;
import com.sz.common.base.dao.schema.TableSchema;
import com.sz.common.base.entity.Entity;
import com.sz.common.base.utils.EntityUtils;
import com.sz.common.base.utils.ReflectHelper;
import com.sz.common.base.utils.TypeConversionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Package: com.sz.common.base.dao.ext.impl <br>
 * Function: TODO: ADD FUNCTION <br>
 * Author: Charles. <br>
 * Date: 2017-02-22 15:18:00.
 */
@Service
public class EntityDaoSupport implements EntityDao {

    @Autowired
    DaoExt dao;

    @Override
    public Object insertEntity(TableSchema tableSchema, Entity entity) {
        if (tableSchema == null || entity == null) {
            throw new IllegalArgumentException("table schema or entity cannot be empty");
        }
        List<Entity> entities = new ArrayList<>();
        entities.add(entity);

        List<Object> ids = this.insertEntities(tableSchema, entities);
        if (ids != null && ids.size() == 1) {
            return ids.get(0);
        }
        return null;
    }

    @Override
    public List<Object> insertEntities(TableSchema tableSchema, List<Entity> entities) {
        if (tableSchema == null) {
            throw new IllegalArgumentException("table schema cannot be empty");
        }
        if (entities == null || entities.size() == 0) {
            throw new IllegalArgumentException("entities cannot be empty");
        }
        List<List<FieldExp>> list = new ArrayList<>();
        for (Object entity : entities) {
            List<FieldExp> fields = FieldExpBuilder.buildFromEntity(tableSchema, entity, true).getFields();
            list.add(fields);
        }
        List<Object> ids = this.dao.insertDataBatch(tableSchema.getTableName(), list);

        if (ids != null && ids.size() == entities.size()) {
            String primaryKey = tableSchema.getPrimaryKeyName();
            Class<?> type = ReflectHelper.getFieldType(entities.get(0).getClass(), primaryKey);
            for (int i = 0; i < ids.size(); i++) {
                Object entity = entities.get(i);
                Object id = ids.get(i);

                Object realId = TypeConversionUtils.covertTo(id, type);
                EntityUtils.setPropertyValue(entity, primaryKey, realId);
            }
        }
        return ids;
    }

    /**
     * @param tableSchema
     * @param entity
     * @param excludeEmptyField
     */
    @Override
    public void updateEntity(TableSchema tableSchema, Entity entity, boolean excludeEmptyField) {
        if (entity == null) {
            throw new IllegalArgumentException("entity cannot be empty");
        }
        List<Entity> entities = new ArrayList<>();
        entities.add(entity);
        this.updateEntities(tableSchema, entities, excludeEmptyField);
    }

    @Override
    public void updateEntities(TableSchema tableSchema, List<Entity> entities, boolean excludeEmptyField) {
        if (tableSchema == null) {
            throw new IllegalArgumentException("table schema cannot be empty");
        }
        if (entities == null || entities.size() == 0) {
            throw new IllegalArgumentException("entities cannot be empty");
        }

        String primaryKey = tableSchema.getPrimaryKeyName();
        if (!StringUtils.hasLength(primaryKey)) {
            throw new IllegalArgumentException("schema table primary Key Name cannot be empty");
        }

        try {
            List<List<FieldExp>> fieldsList = new ArrayList<>();
            List<List<FieldExp>> whereList = new ArrayList<>();
            for (Object entity : entities) {
                Object id = ReflectHelper.getValueByFieldName(entity, primaryKey);
                if (id == null) {
                    throw new IllegalArgumentException("id cannot be empty");
                }
                ReflectHelper.setValueByFieldName(entity, primaryKey, null);

                List<FieldExp> fields = FieldExpBuilder.buildFromEntity(tableSchema, entity, excludeEmptyField).getFields();
                List<FieldExp> where = FieldExpBuilder.add().add(primaryKey, id).getFields();

                fieldsList.add(fields);
                whereList.add(where);
            }

            this.dao.updateDataBatch(tableSchema.getTableName(), fieldsList, whereList);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }


    /**
     * @param tableSchema
     * @param id
     */
    @Override
    public void deleteEntity(TableSchema tableSchema, Serializable id) {
        if (id == null) {
            throw new IllegalArgumentException("id cannot be empty");
        }
        this.deleteEntities(tableSchema, new Serializable[]{id});
    }

    /**
     * @param tableSchema
     * @param ids
     */
    @Override
    public void deleteEntities(TableSchema tableSchema, Serializable[] ids) {
        if (tableSchema == null) {
            throw new IllegalArgumentException("table schema cannot be empty");
        }
        if (ids == null || ids.length == 0) {
            throw new IllegalArgumentException("ids cannot be empty");
        }

        String primaryKey = tableSchema.getPrimaryKeyName();
        if (!StringUtils.hasLength(primaryKey)) {
            throw new IllegalArgumentException("schema table primary Key Name cannot be empty");
        }

        List<List<FieldExp>> list = new ArrayList<>();
        for (Serializable id : ids) {
            List<FieldExp> where = FieldExpBuilder.add().add(primaryKey, id).getFields();
            list.add(where);
        }
        this.dao.deleteDataBatch(tableSchema.getTableName(), list);
    }


    @Override
    public <T> List<T> selectEntities(String tableName, String keyName, Object keyValue, Class<T> clazz) {
        List<FieldExp> whereFields = FieldExpBuilder.add().add(keyName, keyValue).getFields();
        return selectEntities(tableName, whereFields, clazz);
    }

    /**
     * @param tableName
     * @param whereFields
     * @param clazz
     * @param <T>
     * @return
     */
    @Override
    public <T> List<T> selectEntities(String tableName, List<FieldExp> whereFields, Class<T> clazz) {
        List<Map> list = this.dao.selectDataList(tableName, null, whereFields);

        List<T> entities = new ArrayList<T>();
        if (list != null && list.size() > 0) {
            for (Map map : list) {
                T entity = (T) EntityUtils.createEntity(clazz, map);
                entities.add(entity);
            }
        }
        return entities;
    }


    @Override
    public <T> T selectEntity(String tableName, String keyName, Object keyValue, Class<T> clazz) {
        List<FieldExp> whereFields = FieldExpBuilder.add().add(keyName, keyValue).getFields();
        return selectEntity(tableName, whereFields, clazz);
    }

    /**
     * @param tableName
     * @param whereFields
     * @param clazz
     * @param <T>
     * @return
     */
    @Override
    public <T> T selectEntity(String tableName, List<FieldExp> whereFields, Class<T> clazz) {
        Map map = this.dao.selectDataObject(tableName, null, whereFields);
        if (map != null && map.size() > 0) {
            return (T) EntityUtils.createEntity(clazz, map);
        }
        return null;
    }
}
